home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
cpp_libs
/
intrvews
/
xgrab.lha
/
xgrab
/
grabst
/
relay.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-03-06
|
10KB
|
437 lines
/**
GRAB Graph Layout and Browser System
Copyright (c) 1986, 1988 Regents of the University of California
Copyright (c) 1989, Tera Computer Company
**/
/* relay.c - routines to re-layout a graph */
#include "malloc.h"
#include "attribute.h"
#include "digraph.h"
#include "debug.h"
OUTEDGE *get_edge();
INEDGE *get_in_edge();
relay_digraph(digraph)
register DIGRAPH *digraph;
{
/* reset the node's widths */
reset_node_width(digraph);
/* reset ordinalities and directions of edges */
reset_edge_ord(digraph);
/* trash the dummy nodes */
trash_dummy_nodes(digraph);
/* compact the nodes array, i.e. digraph->nodes[] */
compact_nodes_array(digraph);
/* update the vno in the edge lists after compaction */
update_edge_lists_vno(digraph);
/* reset the node fields which need resetting */
reset_nodes(digraph);
/* fix ante and succ sets of the nodes */
fix_ante_succ_sets(digraph);
/* resets fields in digraph */
reset_digraph(digraph);
make_proper(digraph);
minimize_crossings(digraph);
layout_levels(digraph);
}
trash_dummy_nodes(digraph)
register DIGRAPH *digraph;
/* remove the dummy nodes */
{
VNO vno;
register NODE *node;
all_nodes(digraph, node)
loop
if (Is_dummy(node))
{
vno = Vno(node);
dispose(Ante_set(node));
dispose(Succ_set(node));
dispose(Text(node));
dispose_vertex(digraph, Name(node));
dispose(node);
Node(digraph, vno) = NULL;
}
endloop
}
static VNO vno_map[MAXNODES]; /* holds new vno values for the nodes */
#define NO_CHANGE -1
compact_nodes_array(digraph)
register DIGRAPH *digraph;
/* squish the nodes array so the only empty spots are at the end */
{
register int i, j;
for (i = 0; i < MAXNODES; i++)
{
vno_map[i] = NO_CHANGE;
}
for (i = 0, j = 0; i < MAXNODES; i++)
{
if (digraph->nodes[i] == NULL)
{
continue;
}
else if (i == j)
{
j++;
continue;
}
else
{
digraph->nodes[i]->vertex->vno = j;
vno_map[i] = j;
digraph->nodes[j] = digraph->nodes[i];
digraph->nodes[i] = NULL;
j++;
}
}
digraph->lastnode = j - 1;
}
update_edge_lists_vno(digraph)
DIGRAPH *digraph;
/**
update various vno values using vno_map:
coalescer_vno for coalesced nodes
expansion sets for coalescer nodes
from_vno and to_vno fields of in- and out- edges.
**/
{
register NODE *node;
register VNO old_to_vno;
register VNO old_from_vno;
register VNO old_coalescer_vno;
register VNO old_exp_vno;
register INEDGE *in_edge;
register OUTEDGE *out_edge;
SET *old_exp_set;
all_nodes(digraph, node)
loop
if (Coalesced(node))
{
old_coalescer_vno = Coalescer_vno(node);
if (vno_map[old_coalescer_vno] != NO_CHANGE)
{
Coalescer_vno(node) = vno_map[old_coalescer_vno];
}
}
if (Coalescer(node))
{
old_exp_set = Expansion(node);
init_set(Expansion(node));
each_element(old_exp_set, old_exp_vno)
loop
if (vno_map[old_exp_vno] != NO_CHANGE)
{
add_element(Expansion(node), vno_map[old_exp_vno]);
}
else
{
add_element(Expansion(node), old_exp_vno);
}
endloop;
dispose(old_exp_set);
}
all_in_edges(node, in_edge)
loop
old_from_vno = in_edge->from_vno;
if (vno_map[old_from_vno] != NO_CHANGE)
{
in_edge->from_vno = vno_map[old_from_vno];
}
endloop
all_out_edges(node, out_edge)
loop
old_to_vno = out_edge->to_vno;
if (vno_map[old_to_vno] != NO_CHANGE)
{
out_edge->to_vno = vno_map[old_to_vno];
}
endloop
endloop
}
reset_edge_ord(digraph)
DIGRAPH *digraph;
/**
unreverse reversed edges and reset the ordinality of edges.
Unreversing the edges helps put the graph back in a state similar
to when it was read in, which allows the layout routines to layout
the graph in the same way.
**/
{
NODE *node, *next_node;
OUTEDGE *outedge;
INEDGE *inedge;
int max, i, j;
SET *visited;
all_nodes(digraph, node)
loop
if (Is_dummy(node))
{
continue;
}
all_out_edges(node, outedge)
loop
if (Edge_reversed(outedge))
{
reverse_edge(digraph, Vno(node), To_vno(outedge), Ord(outedge));
}
endloop;
endloop;
init_set(visited);
all_nodes(digraph, node)
loop
clear_set(visited);
/**
update the ordinalities using all out edges, which could contain
some repeats. Visited is used to skip repeats. It would be
nicer to use Succ_set, but that could be (probably is) messed
up and won't be fixed until later
**/
all_out_edges(node, outedge)
loop
if (!in(visited, To_vno(outedge)))
{
add_element(visited, To_vno(outedge));
next_node = Node(digraph, To_vno(outedge));
max = max_edges(node, next_node);
j = 1;
for (i = 1; i <= max; i++)
{
if ((outedge = get_edge(digraph, node, next_node, i))
!= NULL)
{
inedge = get_in_edge(digraph, node, next_node, i);
Ord(outedge) = j;
Ord(inedge) = j;
j++;
}
}
}
endloop;
endloop;
dispose(visited);
}
reset_nodes(digraph)
DIGRAPH *digraph;
/* reset node fields that need resetting */
{
register int i;
register NODE *node;
for (i = 0; i <= digraph->lastnode; i++)
{
node = digraph->nodes[i];
dispose(Ante_set(node));
dispose(Succ_set(node));
init_set(Succ_set(node));
init_set(Ante_set(node));
init_member(Node_member(node));
Status(node) = NORMAL; /* dummy nodes are all gone */
Y_position(node) = X_position(node) = 0;
Is_layed(node) = FALSE;
/* halfheight and halfwidth fields already taken care of */
}
}
reset_node_width(digraph)
DIGRAPH *digraph;
/* change the node width, just in case edges have been added/deleted */
{
NODE *node, *node2;
VNO vno;
int max;
all_nodes(digraph, node)
loop
if (Is_dummy(node))
/* dummy nodes are trashed on the next step, so just skip them */
{
continue;
}
max = 0;
each_element(Ante_set(node), vno)
loop
node2 = Node(digraph, vno);
max = MAX(num_edges(node2, node), max);
endloop;
each_element(Succ_set(node), vno)
loop
node2 = Node(digraph, vno);
max = MAX(num_edges(node, node2), max);
endloop;
switch (Shape(node))
{
case POINT:
Half_width(node) = DUMMY_HALF_WIDTH;
break;
case DIAMOND:
Half_width(node) = Node_half_width(node) + HALF_CHAR * 2;
/* 2 extra chars to avoid pinching chars at the end */
break;
case CIRCLE:
Half_width(node) = Node_half_width(node);
break;
case OVAL:
Half_width(node) = Node_half_width(node);
break;
case DOUBLE_BOX:
case RECTANGLE:
Half_width(node) = Node_half_width(node);
break;
default:
PrintError("reset_nodes: illegal shape");
break;
}
fix_width(node, max);
endloop;
}
fix_ante_succ_sets(digraph)
register DIGRAPH *digraph;
/**
use the outedges to properly set the antecedent and succedent sets.
must insure: Displayed edges are in the ante/succ sets.
Coalesced nodes have the proper ante and succ sets (but
no displayed node has a coalesced node in its ante or
succ sets). If coalesced nodes don't have the proper
antecedent and successor sets, expanding a node could
be tricky.
A node is not in its own ante/succ set.
Note that non-displayed nodes (coalesced and hidden nodes) may contain
hidden nodes in their ante/succ sets. As long as this routine is called
after every display/hide/coalesce/expand, this is fine.
**/
{
register NODE *node;
register OUTEDGE *out_edge;
VNO fromvno, tovno;
all_nodes(digraph, node)
loop
if (Coalescer(node) || Is_dummy(node))
/* we only care about nodes with outedges */
{
continue;
}
fromvno = Vno(node);
while (Coalesced(Node(digraph, fromvno)))
/* get the coalescer node which contains this one */
{
fromvno = Coalescer_vno(Node(digraph, fromvno));
}
all_out_edges(node, out_edge)
loop
tovno = To_vno(out_edge);
/**
Get the coalescer node which contains this one.
Along the way, put fromvno in the ancestor sets of the
nodes
**/
while (Coalesced(Node(digraph, tovno)))
{
if (fromvno != tovno)
{
add_element(Node(digraph, tovno)->ante_set, fromvno);
}
tovno = Coalescer_vno(Node(digraph, tovno));
}
/**
We've already got the proper value for fromvno, but
we also need to put tovno in the successor sets for
those nodes, so...
**/
fromvno = Vno(node);
while (Coalesced(Node(digraph, fromvno)))
{
if (fromvno != tovno)
{
add_element(Node(digraph, fromvno)->succ_set, tovno);
}
fromvno = Coalescer_vno(Node(digraph, fromvno));
}
/* add the link for displayed nodes */
if (Displayed(Node(digraph, tovno)) &&
Displayed(Node(digraph, fromvno)) && fromvno != tovno)
{
add_element((Node(digraph, fromvno))->succ_set, tovno);
add_element((Node(digraph, tovno))->ante_set, fromvno);
}
endloop;
endloop;
}
reset_digraph(digraph)
register DIGRAPH *digraph;
{
LEVEL *level;
/* first, free levels structure */
each_level(digraph, level)
loop
dispose(Members(level));
dispose(level);
endloop;
/* now reset some of the fields */
digraph->levels = NULL;
digraph->lastlevel = NULL;
}